package name.manana.jarina;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.apache.log4j.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import com.sun.org.apache.xml.internal.serialize.XMLSerializer;

/**
 * For working with eclipse classpath file.
 * 
 * @author honza
 * 
 */
public class XMLClasspathUtil {
	
	private static final Logger log = Logger.getLogger(XMLClasspathUtil.class);

	private DocumentBuilderFactory factory;
	private Document doc;
	private XPathFactory xpFactory;
	private File file;
	private XPath xpath;

	public XMLClasspathUtil(File fajl) throws IOException {
		this.file = fajl;
		try {
			log.debug("start parsing classpath. ");
			factory = DocumentBuilderFactory.newInstance();
			DocumentBuilder builder = factory.newDocumentBuilder();
			doc = builder.parse(file);
			xpFactory = XPathFactory.newInstance();
			xpath = xpFactory.newXPath();
		} catch (SAXException e) {
			log.error("Unable to parse project classpath file. ",e);
			throw new RuntimeException("classpath file broken?", e);
		} catch (ParserConfigurationException e) {
			log.error("Unable to setup parser for parse project classpath file. ",e);
			throw new RuntimeException("classpath file broken?",e);
		}
	}
	
	public void saveXMLDocument() {
	    try {
	    	log.info("saving classpath file...");
			XMLSerializer serializer = new XMLSerializer();
		    serializer.setOutputCharStream(new FileWriter(file));
			serializer.serialize(doc);
		} catch (IOException e) {
			log.error("unable to save resulting classpath file!");
			throw new RuntimeException("unable to save resulting classpath file", e);
		}
	}

	
	private List<Node> getClasspathentryNodes(String kind) {
		List<Node> result = new ArrayList<Node>();
		XPathExpression expr = null;
		Object xpResult = null;
		try {
			expr = xpath.compile("//classpathentry[@kind='" + kind + "']");
			xpResult = expr.evaluate(doc, XPathConstants.NODESET);
			NodeList nodes = (NodeList) xpResult;
			for (int i = 0; i < nodes.getLength(); i++) {
				result.add(nodes.item(i));
			}
		} catch (XPathExpressionException e) {
			log.error("xpath is broken");
		}
		return result;
	}

	private List<String> getAttributePath(String kind) {
		List<String> result = new ArrayList<String>();
		for (Node node : getClasspathentryNodes(kind)) {
			result.add(node.getAttributes().getNamedItem("path").getTextContent());
		}
		return result;
	}

	/**
	 * @param path
	 * 		new path to add to classpath file
	 */
	public void addClasspathEntry(String path) {
		log.debug("adding classpath entry: " + path);
		if (!getLibDirs().contains(path)) {
			Element el = doc.createElement("classpathentry");
			el.setAttribute("kind", "lib");
			el.setAttribute("path", path);
			doc.getChildNodes().item(0).appendChild(el);
			saveXMLDocument();
		}
	}

	/**
	 * @return allready included paths to jar libs
	 */
	public List<String> getLibDirs() {
		return getAttributePath("lib");
	}

	/**
	 * @return
	 * 		source dirs
	 */
	public List<String> getSourceDirs() {
		return getAttributePath("src");
	}

	public static void main(String[] args) {
		XMLClasspathUtil app;
		try {
			app = new XMLClasspathUtil(new File("TEST_DIRECTORY/.classpath.bak"));
			app.addClasspathEntry("C:/libs/pokus.jar");
			app.addClasspathEntry("C:/libs/pokus.jar");
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
}
